﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;

namespace WindowsFormsApplication1
{
    public class WorldsManager
    {
        private List<WorldMapData> Worlds = new List<WorldMapData>();

        public WorldsManager() { }

        public void AddWorld(WorldMapData wmd)
        {
            lock (Worlds)
            {
                Worlds.Add(wmd);
            }
        }
        public List<WorldMapData> GetWorldsCpy()
        {
            List<WorldMapData> worlds = new List<WorldMapData>();
            lock (Worlds)
            {
                foreach (WorldMapData world in Worlds)
                    worlds.Add(world);
            }
            return worlds;
        }
        public void ServerOffline(ServerSocketData ssd)
        {
            lock (Worlds)
            {
                foreach (WorldMapData world in Worlds)
                {
                    if (world.serverSocketData == ssd)
                        world.serverSocketData = new ServerSocketData(null);
                }
            }
        }
        public void UpdateFromXML(ServerSocketData ssd, string xml)
        {
            lock (Worlds)
            {
                List<OwnedWorld> updateWorlds = new List<OwnedWorld>();
                StringReader sr = new StringReader(xml);
                XmlTextReader xmlReader = new XmlTextReader(sr);
                while (xmlReader.Read())
                {
                    if (xmlReader.Name == "ownedworld")
                    {
                        OwnedWorld world = new OwnedWorld();
                        world.MapID = int.Parse(xmlReader.GetAttribute("mapid").ToString());
                        world.Instance = int.Parse(xmlReader.GetAttribute("instance").ToString());
                        updateWorlds.Add(world);
                    }
                }

                foreach (WorldMapData world in Worlds)
                {
                    bool foundWorld = false;
                    foreach (OwnedWorld updateWorld in updateWorlds)
                    {
                        if (updateWorld.MapID == world.MapID && updateWorld.Instance == world.InstanceID)
                        {
                            foundWorld = true;
                            break;
                        }
                    }
                    if (foundWorld == false)
                    {
                        if (world.serverSocketData == ssd)
                            world.serverSocketData = new ServerSocketData(null);
                    }
                    else
                        world.serverSocketData = ssd;
                }
            }
        }
        public void ChangeServer(List<WorldMapData> worlds, ServerSocketData ssd)
        {
            lock (Worlds)
            {
                //if (worldsChangeRequest.pendingRequest == true)
                //    return;

                WorldsChangeRequest worldsChangeRequest = new WorldsChangeRequest();
                //worldsChangeRequest.pendingRequest = true;

                //Get servers that we are removing worlds from
                List<ServerSocketData> serversToUpdate = new List<ServerSocketData>();
                foreach (WorldMapData world in worlds)
                {
                    if (world.serverSocketData != ssd)
                    {
                        //if this world is not offline send the remove message
                        if (world.Server != "Offline" && serversToUpdate.Contains(world.serverSocketData) == false)
                            serversToUpdate.Add(world.serverSocketData);
                    }
                }

                //Build list of owned worlds for each server that we removed a world from
                foreach (ServerSocketData serverData in serversToUpdate)
                {
                    List<OwnedWorld> serverWorlds = new List<OwnedWorld>();
                    foreach (WorldMapData world in Worlds)
                    {
                        //if this server owns this world and it is not in the list of worlds we have moved then add it to the list
                        if (worlds.Contains(world) == false && world.serverSocketData == serverData)
                        {
                            OwnedWorld ownedWorld = new OwnedWorld();
                            ownedWorld.MapID = world.MapID;
                            ownedWorld.Instance = world.InstanceID;

                            serverWorlds.Add(ownedWorld);
                        }
                    }
                    worldsChangeRequest.addRequest(serverData, serverWorlds);
                }

                //Build list of owned worlds for server we're moving worlds to
                if (ssd.server != "Offline")
                {
                    List<OwnedWorld> serverWorlds2 = new List<OwnedWorld>();
                    foreach (WorldMapData world in Worlds)
                    {
                        if (world.serverSocketData == ssd || worlds.Contains(world))
                        {
                            OwnedWorld ownedWorld = new OwnedWorld();
                            ownedWorld.MapID = world.MapID;
                            ownedWorld.Instance = world.InstanceID;

                            serverWorlds2.Add(ownedWorld);
                        }
                    }
                    worldsChangeRequest.addRequest(ssd, serverWorlds2);
                }

                //Wipe out all the worlds we changed, when the servers
                foreach (WorldMapData world in worlds)
                    world.serverSocketData = new ServerSocketData(null);

                worldsChangeRequest.sendRequests();
            }
        }
        public void GetStartPosition(int MapID, out int StartMapX, out int StartMapY, out int StartMapID)
        {
            StartMapX = -1;
            StartMapY = -1;
            StartMapID = -1;
            lock (this.Worlds)
            {
                foreach (WorldMapData world in Worlds)
                {
                    if (world.MapID == MapID)
                    {
                        StartMapX = world.StartMapX;
                        StartMapY = world.StartMapY;
                        StartMapID = world.StartMapID;
                        break;
                    }
                }
            }
        }
        public ServerSocketData GetServer(int MapID, int Instance)
        {
            lock (Worlds)
            {
                foreach (WorldMapData world in Worlds)
                {
                    if (world.MapID == MapID && world.InstanceID == Instance && world.serverSocketData != null)
                        return world.serverSocketData;
                }
            }
            return new ServerSocketData(null);
        }
    }
    public class OwnedWorld
    {
        public int MapID;
        public int Instance;

        public string toXML()
        {
            return "<ownedworld mapid=\"" + MapID.ToString() + "\" instance=\"" + Instance.ToString() + "\" />";
        }
    }
}
